`ifndef _CONTROLS_V
`define _CONTROLS_V 1

`include "Defines.v"

module CtlRReg(IWORD,RREGNO1,RREGNO2);
  input  wire [31:0] IWORD;
  output wire [3:0] RREGNO1,RREGNO2;
  wire reg1rd=IWORD[31]&&IWORD[28]&&IWORD[24];
  assign RREGNO1=reg1rd?`RD_BITS:`RS_BITS;
  wire reg2rt=(!IWORD[31])&&(!IWORD[30]);
  assign RREGNO2=reg2rt?`RT_BITS:`RD_BITS;
endmodule

module CtlWReg(IWORD,WREGNO,WRREG);
  input  wire [31:0] IWORD;
  output  wire [3:0] WREGNO;
  output  wire WRREG;
  wire isWrReg=(!IWORD[31]&&!IWORD[30]&&IWORD!=32'b0) || (IWORD[31]&&!IWORD[28]) || (IWORD[30]&&!IWORD[29]);
  wire notRETI, notWCTL, notRCTL;
  assign notRETI = (IWORD==32'h80CC0000) ? 1'b0:
							1'b1;
  assign notWCTL = (IWORD[31:24]==8'h70) ? 1'b0:
							1'b1;
  assign notRCTL = (IWORD[31:24]==8'h50) ? 1'b0:
							1'b1;
							
  assign WRREG=(isWrReg) && notRETI && notWCTL && notRCTL;
  assign WREGNO=(isWrReg)?`RD_BITS : `RX_BITS;
endmodule

module CtlImm(IWORD,IMMVAL);
  parameter DBITS;
  input  wire [31:0] IWORD;
  output wire [31:0] IMMVAL;
  wire [31:0] tempImmval={{(DBITS-16){IWORD[15]}},`IM_BITS};
  assign IMMVAL= (IWORD[31])?tempImmval<<2 : tempImmval;
endmodule

module CtlALUIn(IWORD,ALUIN2Z,ALUIN2I);
  input  wire [31:0] IWORD;
  output wire  ALUIN2Z,ALUIN2I;
  wire ax0check = (!IWORD[31]&&!IWORD[30]&&!IWORD[24]) || (IWORD[31]&&IWORD[28]&&!IWORD[24]);//even ALU, BEQ, BNE
  wire a01check = (!IWORD[31]&&!IWORD[30]&&IWORD[24]) || (IWORD[30]) || (IWORD[31] && !IWORD[28]);// alu odd, lw sw, jrl
  wire a11check = (IWORD[31]&&IWORD[28]&&IWORD[24]); //odd branch
  assign {ALUIN2Z,ALUIN2I}=
							(ax0check) ? 2'bX0:
							(a01check) ? 2'b01:
							(a11check) ? 2'b11:
										 2'bXX;
endmodule

module CtlALU(IWORD,
              ALULOG,LOGAND,LOGOR,LOGXOR,LOGNOT,
              ADDSUB,
              ALUCMP,CMPEQ,CMPLT,CMPNOT,
              ALUARI);
	input  wire [31:0] IWORD;
	output wire  ALULOG,LOGAND,LOGOR,LOGXOR,LOGNOT,
				ADDSUB,
				ALUCMP,CMPEQ,CMPLT,CMPNOT,
				ALUARI;
	
	assign ALUCMP = (IWORD[28]);
	assign CMPLT = ALUCMP && (IWORD[26]);
	assign CMPEQ = ALUCMP && !(CMPLT && !IWORD[25]);
	assign CMPNOT = /*ALUCMP && */(CMPEQ && !CMPLT) && IWORD[25];
	
	assign ALUARI = (IWORD[29] || IWORD[30] || (IWORD[31] && !IWORD[28]));
	
	assign ALULOG = (!ALUCMP && !ALUARI);
	assign LOGAND = ((ALULOG) && (!IWORD[27] && !IWORD[26]));
	assign LOGOR = ((ALULOG) && (IWORD[26]));
	assign LOGXOR = ((ALULOG) && (IWORD[27]));
	assign LOGNOT = ((LOGAND && IWORD[25]) || (LOGOR && IWORD[25]));

	assign ADDSUB = (CMPLT) || (ALUARI && IWORD[25]); 
endmodule

module CtlWMem(IWORD,WMEM,RMEM);
  input  wire [31:0] IWORD;
  output wire WMEM,RMEM;
  wire isLW = IWORD[30] && !IWORD[29];
  wire isSW = IWORD[30] && IWORD[29];
  assign WMEM = isSW;
  assign RMEM = isLW;
endmodule

module BraCtl(IWORD,ISBRANCH,ISJUMP,SAVEPC);
  input  wire [31:0] IWORD;
  output wire ISBRANCH,ISJUMP,SAVEPC;
  assign ISBRANCH= (IWORD[31] && IWORD[28]);
  assign ISJUMP=(IWORD[31] && !IWORD[28]);
  assign SAVEPC=ISJUMP && !ISBRANCH && ((IWORD!=32'h80cc0000)) ;
endmodule

module sysCallCtl(IWORD, WRITECTL0, READCTL0, WRITECTL1, READCTL1);
	input [31:0] IWORD;
	output wire WRITECTL0, WRITECTL1;
	output wire READCTL0, READCTL1;
	assign WRITECTL0 = (IWORD[31:28]==4'h7 && `RD_BITS!=4'h1) ? 1'b1: 1'b0;
	assign READCTL0 = (IWORD[31:28]==4'h5 && `RS_BITS!=4'h1) ? 1'b1: 1'b0;
	assign WRITECTL1 = (IWORD[31:28]==4'h7 && `RD_BITS==4'h1) ? 1'b1: 1'b0;
	assign READCTL1 = (IWORD[31:28]==4'h5 && `RS_BITS==4'h1) ? 1'b1: 1'b0;
endmodule

// Determine mode using the instruction word and current mode
// CtlIInst simply looks at the instruction word and decides if it's legal
// in the current mode (cmode_R, which is tied to CTL0[2])
module CtlIInst(IWORD, CMODE, IINST);
	input wire [31:0] IWORD;
	input wire CMODE;
	output reg IINST;
	always@(IWORD or CMODE) begin
		case(`OP_BITS)
			`OP_NAND,`OP_OR,`OP_NOR,`OP_XOR,
			`OP_EQ,`OP_NE,`OP_LT,`OP_LE,
			`OP_ADD,`OP_SUB,
			`OP_ANDI,`OP_NANDI,`OP_ORI,`OP_NORI,`OP_XORI,
			`OP_EQI,`OP_NEI,`OP_LTI,`OP_LEI,
			`OP_ADDI,`OP_SUBI,
			`OP_LW,
			`OP_JRL,
			`OP_BEQZ,`OP_BNEZ, `OP_BNE, `OP_BEQ, `OP_SW,
			`OP_AND: begin
					IINST=1'b0;
			 end
			
			`OP_RCTL,
			`OP_WCTL: begin
					IINST = (!CMODE);
			 end
		default:
			IINST=1'b1;
		endcase
		if(IWORD==32'h80cc0000)
			IINST= (!CMODE);
	end

endmodule


`endif
